package org.linitly.boot.base.utils.jwt;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import org.apache.commons.lang3.StringUtils;
import org.linitly.boot.base.constant.global.JwtConstant;
import org.linitly.boot.base.constant.miniapp.MiniAppCommonConstant;
import org.linitly.boot.base.constant.miniapp.MiniAppJwtConstant;
import org.linitly.boot.base.enums.SystemEnum;
import org.linitly.boot.base.enums.TokenModuleEnum;
import org.linitly.boot.base.utils.auth.AuthFactory;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class JwtMiniAppUtil extends AbstractJwtUtil {

    private static JwtMiniAppUtil jwtMiniAppUtil;

    private JwtMiniAppUtil() {
        super(MiniAppJwtConstant.MINI_APP_ALGORITHM, MiniAppJwtConstant.JWT_SALT, AuthFactory.getAuth(SystemEnum.MINI_APP.getSystemCode()), TokenModuleEnum.SINGLE_TOKEN_EXPIRE);
    }

    public static JwtMiniAppUtil getInstance() {
        if (jwtMiniAppUtil == null) {
            synchronized (JwtMiniAppUtil.class) {
                if (jwtMiniAppUtil == null) {
                    jwtMiniAppUtil = new JwtMiniAppUtil();
                }
            }
        }
        return jwtMiniAppUtil;
    }

    @Override
    public String generateJwt(Map<String, Object> claims, String subject, long expireSecond) {
        claims = claims == null ? new HashMap<>() : claims;
        claims.put(JwtConstant.UUID_JWT_KEY, UUID.randomUUID().toString());
        return Jwts.builder()
                .setSubject(subject)
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + expireSecond * 1000))
                .signWith(algorithm, getKeyInstance())
                .compact();
    }

    @Override
    public String generateToken(String userId, String... message) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(MiniAppJwtConstant.MINI_APP_USER_ID, userId);
        claims.put(MiniAppJwtConstant.SESSION_KEY, StringUtils.isBlank(message[0]) ? null : message[0]);
        claims.put(MiniAppJwtConstant.OPEN_ID, StringUtils.isBlank(message[1]) ? null : message[1]);
        return generateJwt(claims, userId, MiniAppCommonConstant.MINI_APP_TOKEN_EXPIRE_SECOND);
    }

    @Override
    public String generateRefreshToken(String userId, String... message) {
        return null;
    }

    @Override
    public String getToken(HttpServletRequest request) {
        return request == null ? null : request.getHeader(MiniAppCommonConstant.MINI_APP_TOKEN);
    }

    @Override
    public String getRefreshToken(HttpServletRequest request) {
        return null;
    }

    @Override
    public void setTokensHead(String token, String refreshToken) {
        getTokenModuleStrategy().setTokensHead(MiniAppCommonConstant.MINI_APP_TOKEN, null, token, null);
    }

    @Override
    public String getUserId(HttpServletRequest request) {
        String token = getToken(request);
        Map<String, Object> claims = null;
        try {
            claims = parseJwt(token);
        } catch (ExpiredJwtException e) {
            claims = e.getClaims();
        }
        return claims.get(MiniAppJwtConstant.MINI_APP_USER_ID).toString();
    }

    @Override
    public void interceptorValid(HttpServletRequest request) {
        getTokenModuleStrategy().interceptorValid(null);
    }

    @Override
    public void validToken(String token) {
        getTokenModuleStrategy().validToken(token);
    }

    @Override
    public void validExpiredToken(String token) {
        getTokenModuleStrategy().validExpiredToken(token);
    }

    @Override
    public void validRefreshToken(String refreshToken) {
    }

    @Override
    public void generateNewToken() {
        getTokenModuleStrategy().generateNewToken(MiniAppJwtConstant.MINI_APP_USER_ID);
    }
}
